/*
 * SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

extern crate chrono;
extern crate glib;
extern crate gobject_sys;
use crate::common::*;
use gobject_sys::{G_TYPE_INT64, G_TYPE_LONG, G_TYPE_STRING};
use libc::{localtime_r, strftime, time_t};
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_int, c_longlong, c_void};
use std::process::exit;
use std::ptr;
use std::str::FromStr;

// #[link(name = "user")]
// #[link(name = "gobject-2.0")]
// #[link(name = "glib-2.0")]

// Define the function pointer type for `lu_prompt_fn`
pub type lu_prompt_fn = unsafe extern "C" fn(
    prompts: *mut lu_prompt,
    count: c_int,
    callback_data: *mut c_void,
    error: *mut *mut lu_error,
) -> bool;

extern "C" {
    fn g_free(mem: gpointer);
    fn lu_ent_new() -> *mut lu_ent;
    fn lu_ent_free(ent: *mut lu_ent);
    fn lu_ent_get(ent: *mut lu_ent, attribute: *const libc::c_char) -> *mut GValueArray;
    fn lu_ent_get_first_value_strdup(
        ent: *mut lu_ent,
        attribute: *const libc::c_char,
    ) -> *mut libc::c_char;
    fn lu_ent_set_string(ent: *mut lu_ent, attr: *const libc::c_char, value: *const libc::c_char);
    fn lu_ent_set_long(ent: *mut lu_ent, attr: *const libc::c_char, value: libc::c_long);
    fn lu_strerror(error: *mut lu_error) -> *const libc::c_char;
    fn lu_error_free(error: *mut *mut lu_error);
    fn lu_prompt_console(
        prompts: *mut lu_prompt,
        count: libc::c_int,
        callback_data: gpointer,
        error: *mut *mut lu_error,
    ) -> bool;
    fn lu_start(
        authname: *const libc::c_char,
        auth_type: lu_entity_type,
        modules: *const libc::c_char,
        create_modules: *const libc::c_char,
        prompter: Option<lu_prompt_fn>,
        callback_data: gpointer,
        error: *mut *mut lu_error,
    ) -> *mut lu_context;
    fn lu_end(context: *mut lu_context);
    fn lu_user_lookup_name(
        context: *mut lu_context,
        name: *const libc::c_char,
        ent: *mut lu_ent,
        error: *mut *mut lu_error,
    ) -> gboolean;
    fn lu_user_modify(
        context: *mut lu_context,
        ent: *mut lu_ent,
        error: *mut *mut lu_error,
    ) -> gboolean;
    fn lu_user_lock(
        context: *mut lu_context,
        ent: *mut lu_ent,
        error: *mut *mut lu_error,
    ) -> gboolean;
    fn lu_user_unlock(
        context: *mut lu_context,
        ent: *mut lu_ent,
        error: *mut *mut lu_error,
    ) -> gboolean;
    fn lu_user_removepass(
        context: *mut lu_context,
        ent: *mut lu_ent,
        error: *mut *mut lu_error,
    ) -> gboolean;
    fn dcgettext(
        __domainname: *const libc::c_char,
        __msgid: *const libc::c_char,
        __category: libc::c_int,
    ) -> *mut libc::c_char;
}

// Attributes carried by all user structures.
pub const LU_USERNAME: &str = "pw_name";
pub const LU_USERPASSWORD: &str = "pw_passwd";
pub const LU_UIDNUMBER: &str = "pw_uid";
pub const LU_GIDNUMBER: &str = "pw_gid";
pub const LU_GECOS: &str = "pw_gecos";
pub const LU_HOMEDIRECTORY: &str = "pw_dir";
pub const LU_LOGINSHELL: &str = "pw_shell";

// Attributes carried by group structures.
pub const LU_GROUPNAME: &str = "gr_name";
pub const LU_GROUPPASSWORD: &str = "gr_passwd";
pub const LU_MEMBERNAME: &str = "gr_mem";
pub const LU_ADMINISTRATORNAME: &str = "gr_adm";

// Attributes carried by shadow user structures.
pub const LU_SHADOWNAME: &str = LU_USERNAME; // Note: LU_SHADOWNAME is not distinct from LU_USERNAME.
pub const LU_SHADOWPASSWORD: &str = "sp_pwdp";
pub const LU_SHADOWLASTCHANGE: &str = "sp_lstchg";
pub const LU_SHADOWMIN: &str = "sp_min";
pub const LU_SHADOWMAX: &str = "sp_max";
pub const LU_SHADOWWARNING: &str = "sp_warn";
pub const LU_SHADOWINACTIVE: &str = "sp_inact";
pub const LU_SHADOWEXPIRE: &str = "sp_expire";
pub const LU_SHADOWFLAG: &str = "sp_flag";

// Additional fields carried by some structures. If they have them, it's safe to change them.
pub const LU_COMMONNAME: &str = "cn";
pub const LU_GIVENNAME: &str = "givenName";
pub const LU_SN: &str = "sn";
pub const LU_ROOMNUMBER: &str = "roomNumber";
pub const LU_TELEPHONENUMBER: &str = "telephoneNumber";
pub const LU_HOMEPHONE: &str = "homePhone";
pub const LU_EMAIL: &str = "mail";

pub fn strncmp(s1: &str, s2: &str, n: usize) -> i32 {
    let len1 = s1.len();
    let len2 = s2.len();

    let n = n.min(len1).min(len2); // 确保比较长度不超过字符串长度

    let sub1 = &s1[..n];
    let sub2 = &s2[..n];

    if sub1 == sub2 {
        0
    } else {
        sub1.cmp(sub2) as i32 // 将 Ordering 转换为 i32
    }
}

pub fn option_to_ptr(context: Option<lu_context>) -> *mut lu_context {
    match context {
        Some(ptr) => Box::into_raw(Box::new(ptr)),
        None => std::ptr::null_mut(),
    }
}

fn convert_lu_error_ptr(error_ptr: *mut lu_error) -> Option<*mut lu_error> {
    if error_ptr.is_null() {
        None
    } else {
        Some(error_ptr)
    }
}

pub fn check_error(x: Option<*mut lu_error>) -> Result<(), i32> {
    if let Some(mut error_ptr) = x {
        // If the error pointer is not None, print the error and free the error
        let error_str = unsafe {
            if !error_ptr.is_null() {
                // Convert the raw pointer to a CStr, then to a &str
                CStr::from_ptr(lu_strerror(error_ptr))
                    .to_str()
                    .unwrap_or("Invalid UTF-8 string")
            } else {
                "Unknown error"
            }
        };
        // Print the error message
        let progname_name = get_progname_value().unwrap_or_else(|| "utpasswd".to_string());
        unsafe { lu_error_free(&mut error_ptr) };
    }
    Ok(())
}

pub fn shutdown_libuser() {
    unsafe {
        if let Some(context) = get_libuser() {
            //println!("Calling lu_end with valid context");
            lu_end(option_to_ptr(Some(context)));
        } else {
            //println!("No valid context to shut down");
        }
        set_libuser(None);
    }
}

/* Start up the library, suggesting the name of the user which was
 * passed in as the name the library should use if it needs to
 * authenticate to data sources. */
#[allow(clippy::to_string_in_format_args)]
pub fn startup_libuser(user: *const c_char) {
    unsafe {
        let mut error: *mut lu_error = ptr::null_mut();
        if get_libuser().is_none() {
            shutdown_libuser(); // 总是先关闭
        }

        let libuser = lu_start(
            user,
            lu_entity_type::lu_user,
            ptr::null_mut(),
            ptr::null_mut(),
            Some(lu_prompt_console as unsafe extern "C" fn(_, _, _, _) -> bool),
            ptr::null_mut(),
            &mut error,
        );

        if !error.is_null() || get_libuser().is_none() {
            // let progname_str = CStr::from_ptr(get_progname_value().unwrap().as_ptr()).to_string_lossy();
            //eprintln!(
            //    "{}: libuser initialization error:",
            //    get_progname_value().unwrap().to_string(),
            //);
        }

        if !error.is_null() {
            let error_str = CStr::from_ptr(lu_strerror(error)).to_string_lossy();
            eprintln!(" {}---------error.is_null", error_str);
            exit(1);
        }

        if libuser.is_null() {
            eprintln!(" unknown error\n");
            exit(1);
        } else {
            set_libuser(Some((*libuser).clone()));
        }
    }
}

/* Lock an account. */
#[allow(clippy::collapsible_if, temporary_cstring_as_ptr)]
pub fn pwdb_lock_password(username_c: *const c_char) -> c_int {
    let mut retval: c_int = 1;
    let mut ent: *mut lu_ent;
    let mut error: *mut lu_error = ptr::null_mut();
    let mut started: bool = false;

    if get_libuser().is_none() {
        startup_libuser(CString::new("root").unwrap().as_ptr());
        started = true;
    }
    unsafe {
        ent = lu_ent_new();
        if lu_user_lookup_name(
            &mut get_libuser().unwrap() as *mut lu_context,
            username_c,
            ent,
            &mut error,
        ) == 1
        {
            if lu_user_lock(
                &mut get_libuser().unwrap() as *mut lu_context,
                ent,
                &mut error,
            ) == 1
            {
                retval = 0;
            }
        }
        lu_ent_free(ent);
    }

    if !error.is_null() {
        unsafe {
            eprintln!(
                "Error: {}",
                CStr::from_ptr(lu_strerror(error)).to_string_lossy()
            );
        }
    }

    if started {
        shutdown_libuser();
    }
    retval
}

#[allow(
    clippy::collapsible_if,
    clippy::print_literal,
    clippy::to_string_in_format_args,
    temporary_cstring_as_ptr
)]
pub fn pwdb_unlock_password(username_c: *const c_char, force: c_int) -> c_int {
    let mut retval: c_int = 1;
    let mut ent: *mut lu_ent;
    let mut error: *mut lu_error = ptr::null_mut();
    let mut started: bool = false;
    let mut current: *mut c_char = ptr::null_mut();

    if get_libuser().is_none() {
        // unsafe {
        startup_libuser(CString::new("root").unwrap().as_ptr());
        // }
        started = true;
    }
    unsafe {
        ent = lu_ent_new();
        if lu_user_lookup_name(
            &mut get_libuser().unwrap() as *mut lu_context,
            username_c,
            ent,
            &mut error,
        ) == 1
        {
            current = lu_ent_get_first_value_strdup(
                ent,
                CString::new(LU_SHADOWPASSWORD).unwrap().as_ptr(),
            );
            if current.is_null() {
                current = lu_ent_get_first_value_strdup(
                    ent,
                    CString::new(LU_USERPASSWORD).unwrap().as_ptr(),
                );
            }
            if !current.is_null() && force == 0 {
                let current_str = CStr::from_ptr(current).to_bytes();
                let mut i = 0;
                while i < current_str.len() && current_str[i] == b'!' {
                    i += 1;
                }
                if i == current_str.len() {
                    eprintln!(
                        "{}: {}",
                        get_progname_value().unwrap().to_string(),
                        "Warning: unlocked password would be empty."
                    );
                    retval = -2;
                }
            }
            if retval != -2 {
                if lu_user_unlock(
                    &mut get_libuser().unwrap() as *mut lu_context,
                    ent,
                    &mut error,
                ) == 1
                {
                    retval = 0;
                }
            }
        }
        lu_ent_free(ent);
        if !current.is_null() {
            libc::free(current as *mut std::os::raw::c_void);
        }
    }

    if !error.is_null() {
        unsafe {
            eprintln!(
                "Error: {}",
                CStr::from_ptr(lu_strerror(error)).to_string_lossy()
            );
        }
    }

    if started {
        shutdown_libuser();
    }
    retval
}

/* Try to remove a user's password.  Note that some of the underlying modules
 * libuser uses don't support this. */
#[allow(
    clippy::collapsible_if,
    clippy::print_literal,
    clippy::to_string_in_format_args,
    clippy::get_first,
    temporary_cstring_as_ptr
)]
pub fn pwdb_clear_password(username_c: *const c_char) -> c_int {
    let mut retval: c_int = 1;
    let mut ent: *mut lu_ent;
    let mut error: *mut lu_error = ptr::null_mut();
    let mut started: bool = false;
    let mut current: *mut c_char = ptr::null_mut();

    if get_libuser().is_none() {
        // unsafe {
        startup_libuser(CString::new("root").unwrap().as_ptr());
        // }
        started = true;
    }
    unsafe {
        ent = lu_ent_new();
        if lu_user_lookup_name(
            &mut get_libuser().unwrap() as *mut lu_context,
            username_c,
            ent,
            &mut error,
        ) == 1
        {
            current = lu_ent_get_first_value_strdup(
                ent,
                CString::new(LU_SHADOWPASSWORD).unwrap().as_ptr(),
            );
            if current.is_null() {
                current = lu_ent_get_first_value_strdup(
                    ent,
                    CString::new(LU_USERPASSWORD).unwrap().as_ptr(),
                );
            }
            if !current.is_null()
                && *CStr::from_ptr(current).to_bytes().get(0).unwrap_or(&0) == b'!'
            {
                eprintln!(
                    "{}: {}",
                    get_progname_value().unwrap().to_string(),
                    "Note: deleting a password also unlocks the password"
                );
            }
            if lu_user_removepass(
                &mut get_libuser().unwrap() as *mut lu_context,
                ent,
                &mut error,
            ) == 1
            {
                retval = 0;
            }
        }
        lu_ent_free(ent);
        if !current.is_null() {
            libc::free(current as *mut std::os::raw::c_void);
        }
    }

    if !error.is_null() {
        unsafe {
            eprintln!(
                "Error: {}",
                CStr::from_ptr(lu_strerror(error)).to_string_lossy()
            );
        }
    }

    if started {
        shutdown_libuser();
    }
    retval
}

pub fn ent_value_int64(ent: *mut lu_ent, attribute: *const c_char) -> libc::c_longlong {
    if ent.is_null() || attribute.is_null() {
        return 0;
    }

    unsafe {
        let mut value: *mut gobject_sys::GValue = ptr::null_mut();
        let values: *mut gobject_sys::GValueArray =
            lu_ent_get(ent, attribute) as *mut gobject_sys::GValueArray;
        if !values.is_null() {
            value = gobject_sys::g_value_array_get_nth(values, 0);
        }
        if !value.is_null() {
            if gobject_sys::g_type_check_value_holds(value, G_TYPE_STRING) != 0 {
                let c_str_ptr = gobject_sys::g_value_get_string(value);
                if !c_str_ptr.is_null() {
                    let s = CStr::from_ptr(c_str_ptr).to_string_lossy();
                    if let Ok(i) = i64::from_str(&s) {
                        return i as libc::c_longlong;
                    }
                }
            } else if gobject_sys::g_type_check_value_holds(value, G_TYPE_LONG) != 0 {
                return gobject_sys::g_value_get_long(value);
            } else if gobject_sys::g_type_check_value_holds(value, G_TYPE_INT64) != 0 {
                return gobject_sys::g_value_get_int64(value) as libc::c_longlong;
            }
        }
        -1
    }
}

pub fn pwdb_display_status(username_c: *const c_char) -> libc::c_int {
    let mut retval: libc::c_int = 1;
    let mut ent: *mut lu_ent = ptr::null_mut();
    let mut error: *mut lu_error = ptr::null_mut();
    let mut current: *mut c_char = ptr::null_mut();
    let mut current_user: *mut c_char = ptr::null_mut();
    let mut realname: *mut c_char = ptr::null_mut();
    let mut shadow: libc::c_int = 1;
    let mut sp_lstchg: time_t = 0;
    let mut sp_min: c_longlong = 0;
    let mut sp_max: c_longlong = 0;
    let mut sp_warn: c_longlong = 0;
    let mut sp_inact: c_longlong = 0;
    let mut tm = unsafe { std::mem::zeroed() };
    let mut date = [0 as c_char; 80];

    // 创建全局的 CString 变量来存储 status 和 msg 的值
    let mut status_cts = CString::new("").unwrap();
    let mut msg_cts = CString::new("").unwrap();
    let mut status: *const c_char = ptr::null();
    let mut msg: *const c_char = ptr::null();

    unsafe {
        startup_libuser(username_c);
    }
    ent = unsafe { lu_ent_new() };
    if ent.is_null() {
        panic!("Failed to create lu_ent");
    }

    if unsafe {
        lu_user_lookup_name(
            &mut get_libuser().unwrap() as *mut lu_context,
            username_c,
            ent,
            &mut error,
        )
    } != 0
    {
        let mut lu_username_tmp = CString::new(LU_USERNAME).unwrap();
        realname = unsafe { lu_ent_get_first_value_strdup(ent, lu_username_tmp.as_ptr()) };
        if realname.is_null() {
            check_error(convert_lu_error_ptr(error));
            shutdown_libuser();
            return retval;
        }

        let mut lu_shadow_passwd = CString::new(LU_SHADOWPASSWORD).unwrap();
        current = unsafe { lu_ent_get_first_value_strdup(ent, lu_shadow_passwd.as_ptr()) };

        let mut lu_user_passwd = CString::new(LU_USERPASSWORD).unwrap();
        current_user = unsafe { lu_ent_get_first_value_strdup(ent, lu_user_passwd.as_ptr()) };

        if current.is_null() {
            shadow = 0;
            current = current_user;
        } else {
            let mut lu_shadow_last_change = CString::new(LU_SHADOWLASTCHANGE).unwrap();
            sp_lstchg = unsafe { ent_value_int64(ent, lu_shadow_last_change.as_ptr()) };
            let mut lu_shadow_min = CString::new(LU_SHADOWMIN).unwrap();
            sp_min = unsafe { ent_value_int64(ent, lu_shadow_min.as_ptr()) };
            let mut lu_shadow_max = CString::new(LU_SHADOWMAX).unwrap();
            sp_max = unsafe { ent_value_int64(ent, lu_shadow_max.as_ptr()) };
            let mut lu_shadow_warning = CString::new(LU_SHADOWWARNING).unwrap();
            sp_warn = unsafe { ent_value_int64(ent, lu_shadow_warning.as_ptr()) };
            let mut lu_shadow_inactive = CString::new(LU_SHADOWINACTIVE).unwrap();
            sp_inact = unsafe { ent_value_int64(ent, lu_shadow_inactive.as_ptr()) };
        }

        if !current.is_null() {
            // 初始化 status 和 msg
            status_cts = CString::new("PS").unwrap();
            status = status_cts.as_ptr();

            let current_str = unsafe { CStr::from_ptr(current).to_string_lossy() };

            if current_str.len() == 0 {
                msg_cts = CString::new("Empty password.").unwrap();
                msg = msg_cts.as_ptr();
                status_cts = CString::new("NP").unwrap();
                status = status_cts.as_ptr();
            } else if current_str.starts_with('!') {
                msg_cts = CString::new("Password locked.").unwrap();
                msg = msg_cts.as_ptr();
                status_cts = CString::new("LK").unwrap();
                status = status_cts.as_ptr();

                let cstr = unsafe { CStr::from_ptr(status) };
                match cstr.to_str() {
                    Ok(str) => { /* do nothing */ }
                    Err(_) => println!("status contains invalid UTF-8 data"),
                }
            } else if current_str.starts_with('$') {
                if current_str.starts_with("$1$") {
                    msg_cts = CString::new("Password set, MD5 crypt.").unwrap();
                    msg = msg_cts.as_ptr();
                } else if current_str.starts_with("$2a$") {
                    msg_cts = CString::new("Password set, blowfish crypt.").unwrap();
                    msg = msg_cts.as_ptr();
                } else if current_str.starts_with("$5$") {
                    msg_cts = CString::new("Password set, SHA256 crypt.").unwrap();
                    msg = msg_cts.as_ptr();
                } else if current_str.starts_with("$6$") {
                    msg_cts = CString::new("Password set, SHA512 crypt.").unwrap();
                    msg = msg_cts.as_ptr();
                } else if current_str.starts_with("$sm3$") {
                    msg_cts = CString::new("Password set, SM3 crypt.").unwrap();
                    msg = msg_cts.as_ptr();
                } else {
                    msg_cts = CString::new("Password set, unknown crypt variant.").unwrap();
                    msg = msg_cts.as_ptr();
                }
            } else if current_str.len() < 11 {
                msg_cts = CString::new("Alternate authentication scheme in use.").unwrap();
                msg = msg_cts.as_ptr();
                if current_str.starts_with('*') || current_str.starts_with('x') {
                    status_cts = CString::new("LK").unwrap();
                    status = status_cts.as_ptr();
                }
            } else {
                msg_cts = CString::new("Password set, DES crypt.").unwrap();
                msg = msg_cts.as_ptr();
            }

            // 检查 status 的值
            let cstrr = unsafe { CStr::from_ptr(status) };
            match cstrr.to_str() {
                Ok(strr) => { /*空操作*/ }
                Err(_) => println!("status contains invalid UTF-8 data"),
            }

            if shadow != 0 {
                // 安全地处理 CStr 转换为 UTF-8 字符串
                let status_str =
                    unsafe { CStr::from_ptr(status).to_str().unwrap_or("Invalid UTF-8") };
                if status_str.starts_with('N')
                    && !current_user.is_null()
                    && unsafe { CStr::from_ptr(current_user).to_bytes().is_empty() }
                {
                    status_cts = CString::new("NP").unwrap();
                    status = status_cts.as_ptr();
                }

                sp_lstchg *= 24 * 3600;

                unsafe {
                    localtime_r(&sp_lstchg, &mut tm);
                    let mut time_format = CString::new("%Y-%m-%d").unwrap();
                    strftime(date.as_mut_ptr(), date.len(), time_format.as_ptr(), &tm);
                }

                let date_str = unsafe { CStr::from_ptr(date.as_ptr()) }.to_str().unwrap();
                let realname_str =
                    unsafe { CStr::from_ptr(realname).to_str().unwrap_or("Invalid UTF-8") };
                let status_str =
                    unsafe { CStr::from_ptr(status).to_str().unwrap_or("Invalid UTF-8") };
                let msg_str = unsafe { CStr::from_ptr(msg).to_str().unwrap_or("Invalid UTF-8") };

                println!(
                    "{} {} {} {} {} {} {} ({})",
                    realname_str, status_str, date_str, sp_min, sp_max, sp_warn, sp_inact, msg_str
                );
            } else {
                let date_str = unsafe { CStr::from_ptr(date.as_ptr()) }.to_str().unwrap();
                let realname_str =
                    unsafe { CStr::from_ptr(realname).to_str().unwrap_or("Invalid UTF-8") };
                let status_str =
                    unsafe { CStr::from_ptr(status).to_str().unwrap_or("Invalid UTF-8") };
                let msg_str = unsafe { CStr::from_ptr(msg).to_str().unwrap_or("Invalid UTF-8") };
                println!("{} {} ({})", realname_str, status_str, msg_str);
            }

            unsafe { libc::free(current as *mut libc::c_void) };
            if shadow != 0 && !current_user.is_null() {
                unsafe { libc::free(current_user as *mut libc::c_void) };
            }
        } else {
            eprintln!("No password set.");
        }

        unsafe { libc::free(realname as *mut libc::c_void) };
        retval = 0;
    } else {
        println!("Unknown user.");
        retval = 2;
    }

    check_error(convert_lu_error_ptr(error));
    shutdown_libuser();
    retval
}

// pwdb_update_gecos 函数的 Rust 实现
#[allow(clippy::unnecessary_cast, temporary_cstring_as_ptr, unused_must_use)]
pub fn pwdb_update_gecos(username_c: *const libc::c_char, gecos: *const c_char) -> i32 {
    let mut retval = 1;
    let mut ent: *mut lu_ent = ptr::null_mut();
    let mut error: Option<lu_error> = None;

    startup_libuser(username_c);

    // Create a raw pointer to the Option<lu_error> to pass to the C functions
    let error_ptr: *mut *mut lu_error = match &mut error {
        Some(e) => &mut (*e) as *mut lu_error as *mut *mut lu_error,
        None => std::ptr::null_mut(),
    };
    if unsafe {
        lu_user_lookup_name(
            &mut get_libuser().unwrap() as *mut lu_context,
            username_c,
            ent as *mut lu_ent,
            error_ptr,
        ) != 0
    } {
        unsafe {
            lu_ent_set_string(
                ent as *mut lu_ent,
                CString::new(LU_GECOS).unwrap().as_ptr(),
                gecos,
            )
        };

        if unsafe {
            lu_user_modify(
                &mut get_libuser().unwrap() as *mut lu_context,
                ent as *mut lu_ent,
                error_ptr,
            ) != 0
        } {
            retval = 0;
        }
    }

    check_error(error.as_mut().map(|e| e as *mut lu_error));

    shutdown_libuser();
    retval
}

// pwdb_update_shell 函数的 Rust 实现
#[allow(clippy::unnecessary_cast, temporary_cstring_as_ptr, unused_must_use)]
pub fn pwdb_update_shell(
    username_c: *const libc::c_char,
    shell: *const libc::c_char,
) -> libc::c_int {
    let mut retval = 1;
    let mut ent: *mut lu_ent = ptr::null_mut();
    let mut error: Option<lu_error> = None;

    startup_libuser(username_c);
    // Create a raw pointer to the Option<lu_error> to pass to the C functions
    let error_ptr: *mut *mut lu_error = match &mut error {
        Some(e) => &mut (*e) as *mut lu_error as *mut *mut lu_error,
        None => std::ptr::null_mut(),
    };
    if unsafe {
        lu_user_lookup_name(
            &mut get_libuser().unwrap() as *mut lu_context,
            username_c,
            ent as *mut lu_ent,
            error_ptr,
        ) != 0
    } {
        unsafe {
            lu_ent_set_string(
                ent as *mut lu_ent,
                CString::new(LU_LOGINSHELL).unwrap().as_ptr(),
                shell,
            )
        };

        if unsafe {
            lu_user_modify(
                &mut get_libuser().unwrap() as *mut lu_context,
                ent as *mut lu_ent,
                error_ptr,
            ) != 0
        } {
            retval = 0;
        }
    }

    check_error(error.as_mut().map(|e| e as *mut lu_error));

    shutdown_libuser();
    retval
}

// pwdb_update_aging 函数的 Rust 实现
#[allow(
    clippy::print_literal,
    clippy::unnecessary_cast,
    temporary_cstring_as_ptr,
    unused_must_use
)]
pub fn pwdb_update_aging(
    username_c: *const libc::c_char,
    min: i64,
    max: i64,
    warn: i64,
    inact: i64,
    lastchg: i64,
) -> i32 {
    let mut retval = 1;
    let mut ent: *mut lu_ent = ptr::null_mut();
    let mut error: *mut lu_error = ptr::null_mut();

    startup_libuser(username_c);

    unsafe {
        ent = lu_ent_new();
        if ent.is_null() {
            eprintln!("Failed to create lu_ent");
            shutdown_libuser();
            return retval;
        }

        if lu_user_lookup_name(
            &mut get_libuser().unwrap() as *mut lu_context,
            username_c,
            ent,
            &mut error,
        ) != 0
        {
            // 检查用户账户是否支持密码老化
            // 如果所有密码老化字段都不存在，则认为不支持密码老化
            if lu_ent_get(ent, CString::new(LU_SHADOWMIN).unwrap().as_ptr()).is_null()
                && lu_ent_get(ent, CString::new(LU_SHADOWMAX).unwrap().as_ptr()).is_null()
                && lu_ent_get(ent, CString::new(LU_SHADOWWARNING).unwrap().as_ptr()).is_null()
                && lu_ent_get(ent, CString::new(LU_SHADOWINACTIVE).unwrap().as_ptr()).is_null()
            {
                eprintln!(
                    "{}: user account has no support for password aging.",
                    get_progname_value().unwrap()
                );
                lu_ent_free(ent);
                shutdown_libuser();
                return retval;
            }

            if min != -2 {
                lu_ent_set_long(ent, CString::new(LU_SHADOWMIN).unwrap().as_ptr(), min);
            }
            if max != -2 {
                lu_ent_set_long(ent, CString::new(LU_SHADOWMAX).unwrap().as_ptr(), max);
            }
            if warn != -2 {
                lu_ent_set_long(ent, CString::new(LU_SHADOWWARNING).unwrap().as_ptr(), warn);
            }
            if inact != -2 {
                lu_ent_set_long(
                    ent,
                    CString::new(LU_SHADOWINACTIVE).unwrap().as_ptr(),
                    inact,
                );
            }
            if lastchg != -2 {
                lu_ent_set_long(
                    ent,
                    CString::new(LU_SHADOWLASTCHANGE).unwrap().as_ptr(),
                    lastchg,
                );
            }

            if lu_user_modify(
                &mut get_libuser().unwrap() as *mut lu_context,
                ent,
                &mut error,
            ) != 0
            {
                retval = 0;
            }
        }

        lu_ent_free(ent);
    }

    if !error.is_null() {
        unsafe {
            eprintln!(
                "Error: {}",
                CStr::from_ptr(lu_strerror(error)).to_string_lossy()
            );
            lu_error_free(&mut error);
        }
    }

    shutdown_libuser();
    retval
}

#[cfg(test)]
mod tests {
    #![allow(
        clippy::nonminimal_bool,
        clippy::unnecessary_cast,
        unused_must_use,
        temporary_cstring_as_ptr,
        clippy::unnecessary_cast
    )]
    use super::*;
    // use crate::common::*;
    use std::ffi::CString;
    use std::ptr;

    #[test]
    fn test_equal_strings() {
        assert_eq!(strncmp("hello", "hello", 5), 0);
    }

    #[test]
    fn test_different_strings() {
        assert!(strncmp("apple", "banana", 5) < 0);
        assert!(strncmp("banana", "apple", 5) > 0);
    }

    #[test]
    fn test_partial_comparison() {
        assert_eq!(strncmp("hello", "hello world", 5), 0);
        assert!(strncmp("apple", "application", 3) < 0);
    }

    #[test]
    fn test_zero_length() {
        assert_eq!(strncmp("any", "string", 0), 0);
    }

    #[test]
    fn test_unicode_strings() {
        assert_eq!(strncmp("中文", "中文", 2), 0);
        assert!(strncmp("中文", "英文", 1) != 0);
    }

    #[test]
    fn test_n_greater_than_length() {
        assert_eq!(strncmp("short", "short", 10), 0);
        assert!(strncmp("short", "longer", 10) < 0);
    }

    #[test]
    fn test_option_to_ptr_with_some() {
        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }

        let context = lu_context {
            scache: ptr::null_mut(),
            auth_name: ptr::null_mut(),
            auth_type: lu_entity_type::lu_invalid,
            config: ptr::null_mut(),
            prompter: dummy_prompter,
            prompter_data: ptr::null_mut(),
            module_names: ptr::null_mut(),
            create_module_names: ptr::null_mut(),
            modules: ptr::null_mut(),
        };

        let ptr = option_to_ptr(Some(context));
        assert!(!ptr.is_null());
        unsafe { Box::from_raw(ptr) }; // 回收内存
    }

    #[test]
    fn test_option_to_ptr_with_none() {
        let ptr = option_to_ptr(None);
        assert!(ptr.is_null());
    }

    #[test]
    fn test_ptr_validity_after_conversion() {
        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }

        let context = lu_context {
            scache: ptr::null_mut(),
            auth_name: ptr::null_mut(),
            auth_type: lu_entity_type::lu_invalid,
            config: ptr::null_mut(),
            prompter: dummy_prompter,
            prompter_data: ptr::null_mut(),
            module_names: ptr::null_mut(),
            create_module_names: ptr::null_mut(),
            modules: ptr::null_mut(),
        };

        let ptr = option_to_ptr(Some(context));
        unsafe {
            assert_eq!((*ptr).auth_type, lu_entity_type::lu_invalid);
            Box::from_raw(ptr); // 回收内存
        }
    }

    #[test]
    fn test_check_error_with_null() {
        assert!(check_error(None).is_ok());
    }

    fn test_check_error_with_valid_error() {
        let error_str = CString::new("Test error").unwrap();
        let mut error_ptr = Box::into_raw(Box::new(lu_error {
            code: lu_status::lu_error_generic, // Use appropriate error code
            string: error_str.into_raw(),      // Convert to raw pointer
        }));

        let result = check_error(Some(error_ptr));
        assert!(result.is_ok());

        // Clean up - since we converted to raw pointer, we need to reconstruct to drop properly
        unsafe {
            let _ = CString::from_raw((*error_ptr).string);
            let _ = Box::from_raw(error_ptr);
        }
    }

    #[test]
    fn test_check_error_with_null_error_ptr() {
        let result = check_error(Some(ptr::null_mut()));
        assert!(result.is_ok());
    }

    #[test]
    fn test_check_error_with_invalid_utf8() {
        let invalid_str = b"Invalid\xFFUTF8";
        let error_str = unsafe { CString::from_vec_unchecked(invalid_str.to_vec()) };
        let mut error_ptr = Box::into_raw(Box::new(lu_error {
            code: lu_status::lu_error_generic, // Use appropriate error code
            string: error_str.into_raw(),      // Convert to raw pointer
        }));

        let result = check_error(Some(error_ptr));
        assert!(result.is_ok());

        // Clean up - since we converted to raw pointer, we need to reconstruct to drop properly
        unsafe {
            let _ = CString::from_raw((*error_ptr).string);
            let _ = Box::from_raw(error_ptr);
        }
    }

    #[test]
    fn test_shutdown_with_context() {
        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }
        // 设置测试上下文
        let ctx = lu_context {
            scache: ptr::null_mut(),
            auth_name: ptr::null_mut(),
            auth_type: lu_entity_type::lu_invalid,
            config: ptr::null_mut(),
            prompter: dummy_prompter,
            prompter_data: ptr::null_mut(),
            module_names: ptr::null_mut(),
            create_module_names: ptr::null_mut(),
            modules: ptr::null_mut(),
        };
        set_libuser(Some(ctx));

        shutdown_libuser();

        assert!(get_libuser().is_none());
    }

    #[test]
    fn test_shutdown_without_context() {
        // 确保初始状态为None
        set_libuser(None);

        shutdown_libuser();

        assert!(get_libuser().is_none());
    }

    #[test]
    fn test_shutdown_null_context() {
        // 设置空指针上下文
        // unsafe {
        set_libuser(None);
        // }

        shutdown_libuser();

        assert!(get_libuser().is_none());
    }

    #[test]
    #[allow(clippy::nonminimal_bool)]
    fn test_startup_success() {
        let user = CString::new("testuser").unwrap();

        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }

        unsafe {
            // 模拟lu_start返回有效上下文
            let mock_ctx = Box::into_raw(Box::new(lu_context {
                scache: ptr::null_mut(),
                auth_name: ptr::null_mut(),
                auth_type: lu_entity_type::lu_user,
                config: ptr::null_mut(),
                prompter: dummy_prompter,
                prompter_data: ptr::null_mut(),
                module_names: ptr::null_mut(),
                create_module_names: ptr::null_mut(),
                modules: ptr::null_mut(),
            }));

            startup_libuser(user.as_ptr());
            assert!(!get_libuser().is_none());
            Box::from_raw(mock_ctx); // 清理内存
        }
    }

    #[test]
    fn test_startup_with_error() {
        let user = CString::new("testuser").unwrap();
        unsafe {
            // 模拟lu_start返回错误
            let error_str = CString::new("Test error").unwrap();
            let mut error_ptr = Box::into_raw(Box::new(lu_error {
                code: lu_status::lu_error_generic, // 使用适当的错误代码
                string: error_str.into_raw(),      // 转换为原始指针
            }));

            startup_libuser(user.as_ptr());
            // 验证错误处理路径

            // 清理内存 - 需要先重建CString再释放
            let _ = CString::from_raw((*error_ptr).string);
            let _ = Box::from_raw(error_ptr);
        }
    }

    #[test]
    fn test_startup_null_context() {
        let user = CString::new("testuser").unwrap();
        // unsafe {
        // 模拟lu_start返回空指针
        startup_libuser(user.as_ptr());
        // 验证空指针处理路径
        // }
    }

    #[test]
    fn test_startup_with_existing_context() {
        let user = CString::new("testuser").unwrap();
        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }
        unsafe {
            // 先设置一个现有上下文
            let existing_ctx = Box::into_raw(Box::new(lu_context {
                scache: ptr::null_mut(),
                auth_name: ptr::null_mut(),
                auth_type: lu_entity_type::lu_user,
                config: ptr::null_mut(),
                prompter: dummy_prompter,
                prompter_data: ptr::null_mut(),
                module_names: ptr::null_mut(),
                create_module_names: ptr::null_mut(),
                modules: ptr::null_mut(),
            }));
            set_libuser(Some((*existing_ctx).clone()));

            startup_libuser(user.as_ptr());
            assert!(!get_libuser().is_none());
            Box::from_raw(existing_ctx); // 清理内存
        }
    }

    #[test]
    fn test_pwdb_lock_password_success() {
        let username_test = CString::new("testuser").unwrap();
        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }
        unsafe {
            // 模拟成功查找和锁定
            let mock_ctx = Box::into_raw(Box::new(lu_context {
                scache: ptr::null_mut(),
                auth_name: ptr::null_mut(),
                auth_type: lu_entity_type::lu_user,
                config: ptr::null_mut(),
                prompter: dummy_prompter,
                prompter_data: ptr::null_mut(),
                module_names: ptr::null_mut(),
                create_module_names: ptr::null_mut(),
                modules: ptr::null_mut(),
            }));
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_lock_password(username_test.as_ptr()), 0);
            Box::from_raw(mock_ctx); // 清理内存
        }
    }

    #[test]
    fn test_pwdb_lock_password_lookup_failure() {
        let username_test = CString::new("nonexist").unwrap();
        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }

        unsafe {
            // 模拟查找失败
            let mock_ctx = Box::into_raw(Box::new(lu_context {
                scache: ptr::null_mut(),
                auth_name: ptr::null_mut(),
                auth_type: lu_entity_type::lu_user,
                config: ptr::null_mut(),
                prompter: dummy_prompter,
                prompter_data: ptr::null_mut(),
                module_names: ptr::null_mut(),
                create_module_names: ptr::null_mut(),
                modules: ptr::null_mut(),
            }));
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_lock_password(username_test.as_ptr()), 1);
            Box::from_raw(mock_ctx); // 清理内存
        }
    }

    #[test]
    fn test_pwdb_lock_password_lock_failure() {
        let username_test = CString::new("lockeduser").unwrap();
        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }
        unsafe {
            // 模拟查找成功但锁定失败
            let mock_ctx = Box::into_raw(Box::new(lu_context {
                scache: ptr::null_mut(),
                auth_name: ptr::null_mut(),
                auth_type: lu_entity_type::lu_user,
                config: ptr::null_mut(),
                prompter: dummy_prompter,
                prompter_data: ptr::null_mut(),
                module_names: ptr::null_mut(),
                create_module_names: ptr::null_mut(),
                modules: ptr::null_mut(),
            }));
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_lock_password(username_test.as_ptr()), 1);
            Box::from_raw(mock_ctx); // 清理内存
        }
    }

    #[test]
    fn test_pwdb_lock_password_with_error() {
        let username_test = CString::new("erroruser").unwrap();
        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }

        unsafe {
            // 模拟错误情况
            let mock_ctx = Box::into_raw(Box::new(lu_context {
                scache: ptr::null_mut(),
                auth_name: ptr::null_mut(),
                auth_type: lu_entity_type::lu_user,
                config: ptr::null_mut(),
                prompter: dummy_prompter,
                prompter_data: ptr::null_mut(),
                module_names: ptr::null_mut(),
                create_module_names: ptr::null_mut(),
                modules: ptr::null_mut(),
            }));
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_lock_password(username_test.as_ptr()), 1);
            Box::from_raw(mock_ctx); // 清理内存
        }
    }

    #[test]
    fn test_pwdb_lock_password_auto_startup() {
        let username_test = CString::new("newuser").unwrap();
        set_libuser(None); // 确保没有上下文

        // unsafe {
        assert_eq!(pwdb_lock_password(username_test.as_ptr()), 1);
        // }
    }

    #[test]
    fn test_pwdb_unlock_password_success() {
        let username_test = CString::new("testuser").unwrap();
        unsafe {
            // 模拟成功解锁
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_unlock_password(username_test.as_ptr(), 0), 0);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_unlock_password_empty_warning() {
        let username_test = CString::new("emptyuser").unwrap();
        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_unlock_password(username_test.as_ptr(), 0), -2);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_unlock_password_force() {
        let username_test = CString::new("forceuser").unwrap();
        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_unlock_password(username_test.as_ptr(), 1), 0);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_unlock_password_lookup_failure() {
        let username_test = CString::new("nonexist").unwrap();
        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_unlock_password(username_test.as_ptr(), 0), 1);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_unlock_password_auto_startup() {
        let username_test = CString::new("newuser").unwrap();
        set_libuser(None);

        // unsafe {
        assert_eq!(pwdb_unlock_password(username_test.as_ptr(), 0), 1);
        // }
    }

    unsafe fn create_mock_context() -> *mut lu_context {
        fn dummy_prompter(
            _prompts: *mut lu_prompt,
            _count: i32,
            _callback_data: *mut c_void,
            _error: *mut Option<lu_error>,
        ) -> bool {
            false
        }

        Box::into_raw(Box::new(lu_context {
            scache: ptr::null_mut(),
            auth_name: ptr::null_mut(),
            auth_type: lu_entity_type::lu_user,
            config: ptr::null_mut(),
            prompter: dummy_prompter,
            prompter_data: ptr::null_mut(),
            module_names: ptr::null_mut(),
            create_module_names: ptr::null_mut(),
            modules: ptr::null_mut(),
        }))
    }

    #[test]
    fn test_pwdb_clear_password_success() {
        let username_test = CString::new("testuser").unwrap();
        unsafe {
            // 模拟成功清除密码
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_clear_password(username_test.as_ptr()), 0);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_clear_password_locked_account() {
        let username_test = CString::new("lockeduser").unwrap();
        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_clear_password(username_test.as_ptr()), 0);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_clear_password_lookup_failure() {
        let username_test = CString::new("nonexist").unwrap();
        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_clear_password(username_test.as_ptr()), 1);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_clear_password_remove_failure() {
        let username_test = CString::new("failuser").unwrap();
        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_clear_password(username_test.as_ptr()), 1);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_clear_password_auto_startup() {
        let username_test = CString::new("newuser").unwrap();
        set_libuser(None);

        // unsafe {
        assert_eq!(pwdb_clear_password(username_test.as_ptr()), 1);
        // }
    }

    #[test]
    fn test_ent_value_int64_from_string() {
        let attr = CString::new("test_attr").unwrap();
        unsafe {
            // 模拟字符串类型值
            let mock_ent = create_mock_ent(
                Some("123"), // password
                None,        // username_test
                None,        // last_change
                None,        // min
                None,        // max
                None,        // warn
                None,        // inact
            );
            assert_eq!(ent_value_int64(mock_ent, attr.as_ptr()), 123);
            free_mock_ent(mock_ent);
        }
    }

    #[test]
    fn test_ent_value_int64_from_long() {
        let attr = CString::new("test_attr").unwrap();
        unsafe {
            // 模拟long类型值
            let mock_ent = create_mock_ent(
                None,      // password
                None,      // username_test
                None,      // last_change
                Some(456), // min (using 456 to match expected test value)
                None,      // max
                None,      // warn
                None,      // inact
            );
            assert_eq!(ent_value_int64(mock_ent, attr.as_ptr()), 456);
            free_mock_ent(mock_ent);
        }
    }

    #[test]
    fn test_ent_value_int64_from_int64() {
        let attr = CString::new("test_attr").unwrap();
        unsafe {
            // 模拟int64类型值
            let mock_ent = create_mock_ent(
                None,      // password
                None,      // username_test
                None,      // last_change
                None,      // min
                None,      // max
                None,      // warn
                Some(789), // inact (using 789 to match expected test value)
            );
            assert_eq!(ent_value_int64(mock_ent, attr.as_ptr()), 789);
            free_mock_ent(mock_ent);
        }
    }

    #[test]
    fn test_ent_value_int64_invalid_string() {
        let attr = CString::new("test_attr").unwrap();
        unsafe {
            // 模拟无效字符串值
            let mock_ent = create_mock_ent(
                Some("abc"), // password
                None,        // username_test
                None,        // last_change
                None,        // min
                None,        // max
                None,        // warn
                None,        // inact
            );
            assert_eq!(ent_value_int64(mock_ent, attr.as_ptr()), -1);
            free_mock_ent(mock_ent);
        }
    }

    #[test]
    fn test_ent_value_int64_null_values() {
        let attr = CString::new("test_attr").unwrap();
        // unsafe {
        // 模拟空值情况
        let mock_ent = ptr::null_mut();
        assert_eq!(ent_value_int64(mock_ent, attr.as_ptr()), -1);
        // }
    }

    unsafe fn free_mock_ent(ent: *mut lu_ent) {
        if !ent.is_null() {
            Box::from_raw(ent);
        }
    }

    #[test]
    fn test_pwdb_display_status_valid_user() {
        let username_test = CString::new("testuser").unwrap();
        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent = create_mock_ent(
                Some("password"),
                Some("testuser"),
                Some(0),     // shadowLastChange
                Some(0),     // shadowMin
                Some(99999), // shadowMax
                Some(7),     // shadowWarning
                Some(-1),    // shadowInactive
            );

            assert_eq!(pwdb_display_status(username_test.as_ptr()), 0);

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_display_status_locked_password() {
        let username_test = CString::new("lockeduser").unwrap();
        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent = create_mock_ent(
                Some("!password"),
                Some("lockeduser"),
                Some(0),
                Some(0),
                Some(99999),
                Some(7),
                Some(-1),
            );

            assert_eq!(pwdb_display_status(username_test.as_ptr()), 0);

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_display_status_empty_password() {
        let username_test = CString::new("emptyuser").unwrap();
        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent =
                create_mock_ent(Some(""), Some("emptyuser"), None, None, None, None, None);

            assert_eq!(pwdb_display_status(username_test.as_ptr()), 0);

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_display_status_unknown_user() {
        let username_test = CString::new("nonexist").unwrap();
        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_display_status(username_test.as_ptr()), 2);

            Box::from_raw(mock_ctx);
        }
    }

    unsafe fn create_mock_ent(
        password: Option<&str>,
        username_test: Option<&str>,
        last_change: Option<i64>,
        min: Option<i64>,
        max: Option<i64>,
        warn: Option<i64>,
        inact: Option<i64>,
    ) -> *mut lu_ent {
        let ent = Box::into_raw(Box::new(lu_ent {
            magic: 0xDEADBEEF, // 魔数标识
            entity_type: lu_entity_type::lu_user,
            cache: ptr::null_mut(),
            current: ptr::null_mut(),
            pending: ptr::null_mut(),
            modules: ptr::null_mut(),
        }));

        // 设置密码字段
        if let Some(pwd) = password {
            lu_ent_set_string(
                ent,
                CString::new(LU_SHADOWPASSWORD).unwrap().as_ptr(),
                CString::new(pwd).unwrap().as_ptr(),
            );
        }

        // 设置用户名
        if let Some(name) = username_test {
            lu_ent_set_string(
                ent,
                CString::new(LU_USERNAME).unwrap().as_ptr(),
                CString::new(name).unwrap().as_ptr(),
            );
        }

        // 设置密码老化相关字段
        if let Some(lc) = last_change {
            lu_ent_set_long(ent, CString::new(LU_SHADOWLASTCHANGE).unwrap().as_ptr(), lc);
        }
        if let Some(m) = min {
            lu_ent_set_long(ent, CString::new(LU_SHADOWMIN).unwrap().as_ptr(), m);
        }
        if let Some(m) = max {
            lu_ent_set_long(ent, CString::new(LU_SHADOWMAX).unwrap().as_ptr(), m);
        }
        if let Some(w) = warn {
            lu_ent_set_long(ent, CString::new(LU_SHADOWWARNING).unwrap().as_ptr(), w);
        }
        if let Some(i) = inact {
            lu_ent_set_long(ent, CString::new(LU_SHADOWINACTIVE).unwrap().as_ptr(), i);
        }

        ent
    }

    #[test]
    fn test_pwdb_update_gecos_success() {
        let username_test = CString::new("testuser").unwrap();
        let gecos = CString::new("Test User").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent = create_mock_ent(
                None, // password
                None, // username_test
                None, // last_change
                None, // min
                None, // max
                None, // warn
                None, // inact
            );

            assert_eq!(pwdb_update_gecos(username_test.as_ptr(), gecos.as_ptr()), 0);

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_update_gecos_lookup_failure() {
        let username_test = CString::new("nonexist").unwrap();
        let gecos = CString::new("Test User").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_update_gecos(username_test.as_ptr(), gecos.as_ptr()), 1);

            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_update_gecos_modify_failure() {
        let username_test = CString::new("failuser").unwrap();
        let gecos = CString::new("Test User").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent = create_mock_ent(
                None, // password
                None, // username_test
                None, // last_change
                None, // min
                None, // max
                None, // warn
                None, // inact
            );

            assert_eq!(pwdb_update_gecos(username_test.as_ptr(), gecos.as_ptr()), 1);

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_update_gecos_empty_gecos() {
        let username_test = CString::new("testuser").unwrap();
        let gecos = CString::new("").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent = create_mock_ent(
                None, // password
                None, // username_test
                None, // last_change
                None, // min
                None, // max
                None, // warn
                None, // inact
            );

            assert_eq!(pwdb_update_gecos(username_test.as_ptr(), gecos.as_ptr()), 0);

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_update_shell_success() {
        let username_test = CString::new("testuser").unwrap();
        let shell = CString::new("/bin/bash").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent = create_mock_ent(
                None, // password
                None, // username_test
                None, // last_change
                None, // min
                None, // max
                None, // warn
                None, // inact
            );

            assert_eq!(pwdb_update_shell(username_test.as_ptr(), shell.as_ptr()), 0);

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_update_shell_lookup_failure() {
        let username_test = CString::new("nonexist").unwrap();
        let shell = CString::new("/bin/bash").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(pwdb_update_shell(username_test.as_ptr(), shell.as_ptr()), 1);

            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_update_shell_modify_failure() {
        let username_test = CString::new("failuser").unwrap();
        let shell = CString::new("/bin/bash").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent = create_mock_ent(
                None, // password
                None, // username_test
                None, // last_change
                None, // min
                None, // max
                None, // warn
                None, // inact
            );

            assert_eq!(pwdb_update_shell(username_test.as_ptr(), shell.as_ptr()), 1);

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_update_shell_empty_shell() {
        let username_test = CString::new("testuser").unwrap();
        let shell = CString::new("").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent = create_mock_ent(
                None, // password
                None, // username_test
                None, // last_change
                None, // min
                None, // max
                None, // warn
                None, // inact
            );

            assert_eq!(pwdb_update_shell(username_test.as_ptr(), shell.as_ptr()), 0);

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_update_aging_success() {
        let username_test = CString::new("testuser").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent = create_mock_ent(
                None, // password
                None, // username_test
                None, // last_change
                None, // min
                None, // max
                None, // warn
                None, // inact
            );

            assert_eq!(
                pwdb_update_aging(username_test.as_ptr(), 0, 99999, 7, -1, 0),
                0
            );

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_update_aging_no_aging_support() {
        let username_test = CString::new("noaging").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent = create_mock_ent(
                None, // password
                None, // username_test
                None, // last_change
                None, // min
                None, // max
                None, // warn
                None, // inact
            );

            assert_eq!(
                pwdb_update_aging(username_test.as_ptr(), 0, 99999, 7, -1, 0),
                1
            );

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_update_aging_partial_update() {
        let username_test = CString::new("partial").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            let mock_ent = create_mock_ent(
                None, // password
                None, // username_test
                None, // last_change
                None, // min
                None, // max
                None, // warn
                None, // inact
            );

            assert_eq!(
                pwdb_update_aging(username_test.as_ptr(), -2, 99999, -2, -1, 0),
                0
            );

            free_mock_ent(mock_ent);
            Box::from_raw(mock_ctx);
        }
    }

    #[test]
    fn test_pwdb_update_aging_lookup_failure() {
        let username_test = CString::new("nonexist").unwrap();

        unsafe {
            let mock_ctx = create_mock_context();
            set_libuser(Some((*mock_ctx).clone()));

            assert_eq!(
                pwdb_update_aging(username_test.as_ptr(), 0, 99999, 7, -1, 0),
                1
            );

            Box::from_raw(mock_ctx);
        }
    }
}
